package com.dream.oauth2.security;

import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Map;

@Slf4j
public class QQOAuth2AccessTokenResponseClient implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {

    private final RestTemplate restTemplate;

    public QQOAuth2AccessTokenResponseClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) {
        try {
            // 构建请求参数
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            parameters.add("grant_type", authorizationGrantRequest.getGrantType().getValue());
            parameters.add("code", authorizationGrantRequest.getAuthorizationExchange().getAuthorizationResponse().getCode());
            parameters.add("redirect_uri", authorizationGrantRequest.getAuthorizationExchange().getAuthorizationRequest().getRedirectUri());
            parameters.add("client_id", authorizationGrantRequest.getClientRegistration().getClientId());
            parameters.add("client_secret", authorizationGrantRequest.getClientRegistration().getClientSecret());

            // 构建请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            // 发送请求
            String tokenUrl = authorizationGrantRequest.getClientRegistration().getProviderDetails().getTokenUri();
            log.info("请求QQ token URL: {}", tokenUrl);
            String response = restTemplate.postForObject(tokenUrl, new HttpEntity<>(parameters, headers), String.class);
            log.info("获取到QQ token响应: {}", response);

            // 解析URL编码的表单数据
            Map<String, String> responseMap = UriComponentsBuilder.fromUriString("?" + response)
                    .build()
                    .getQueryParams()
                    .toSingleValueMap();

            // 检查错误
            if (responseMap.containsKey("error")) {
                throw new RuntimeException("QQ token获取失败: " + responseMap.get("error") + " - " + responseMap.get("error_description"));
            }

            String accessToken = responseMap.get("access_token");
            String openid = getOpenid(accessToken);
            log.info("获取到QQ openid: {}", openid);

            // 获取用户信息
            JSONObject userJson = getUserInfo(accessToken, openid, authorizationGrantRequest.getClientRegistration().getClientId());
            log.info("获取到QQ用户信息: {}", userJson);

            // 昵称
            String nickname = userJson.getString("nickname");
            // 头像
            String avatar = userJson.getString("figureurl_qq_2");

            // 构建OAuth2AccessTokenResponse
            return OAuth2AccessTokenResponse.withToken(accessToken)
                    .tokenType(OAuth2AccessToken.TokenType.BEARER)
                    .expiresIn(Long.parseLong(responseMap.get("expires_in")))
                    .refreshToken(responseMap.get("refresh_token"))
                    .additionalParameters(Map.of(
                        "openid", openid,
                        "nickname", nickname,
                        "figureurl_qq_2", avatar
                    ))
                    .build();
        } catch (Exception e) {
            log.error("QQ token获取失败", e);
            throw new RuntimeException("QQ token获取失败: " + e.getMessage());
        }
    }

    private String getOpenid(String accessToken) {
        try {
            String openidUrl = String.format("https://graph.qq.com/oauth2.0/me?access_token=%s", accessToken);
            log.info("请求QQ openid URL: {}", openidUrl);
            String response = restTemplate.getForObject(openidUrl, String.class);
            log.info("获取到QQ openid响应: {}", response);

            // 解析JSONP响应
            int start = response.indexOf("(") + 1;
            int end = response.lastIndexOf(")");
            if (start > 0 && end > start) {
                String jsonStr = response.substring(start, end);
                JSONObject json = JSONObject.parseObject(jsonStr);
                String openid = json.getString("openid");
                if (openid == null || openid.isEmpty()) {
                    throw new RuntimeException("openid为空");
                }
                return openid;
            }
            throw new RuntimeException("无效的openid响应格式");
        } catch (Exception e) {
            log.error("获取QQ openid失败", e);
            throw new RuntimeException("获取QQ openid失败: " + e.getMessage());
        }
    }

    private JSONObject getUserInfo(String accessToken, String openid, String clientId) {
        try {
            String userInfoUrl = String.format(
                "https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s",
                accessToken, clientId, openid
            );
            log.info("请求QQ用户信息URL: {}", userInfoUrl);
            String response = restTemplate.getForObject(userInfoUrl, String.class);
            log.info("获取到QQ用户信息响应: {}", response);

            JSONObject json = JSONObject.parseObject(response);
            if (json.containsKey("ret") && json.getIntValue("ret") != 0) {
                throw new RuntimeException("获取用户信息失败: " + json.getString("msg"));
            }
//            String nickname = json.getString("nickname");
//            if (nickname == null || nickname.isEmpty()) {
//                throw new RuntimeException("用户昵称为空");
//            }
            return json;
        } catch (Exception e) {
            log.error("获取QQ用户信息失败", e);
            throw new RuntimeException("获取QQ用户信息失败: " + e.getMessage());
        }
    }
} 